#include "account_manager.h"
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <sstream>

using namespace std;

AccountManager::AccountManager(const string& account_file) 
    : account_file_path(account_file) {
    loadAccountsFromFile();
}

string AccountManager::generateSalt() const {
    const int SALT_LENGTH = 16;
    unsigned char salt_bytes[SALT_LENGTH];
    RAND_bytes(salt_bytes, SALT_LENGTH);
    return hexEncode(salt_bytes, SALT_LENGTH);
}

string AccountManager::hexEncode(const unsigned char* data, size_t len) const {
    stringstream ss;
    for (size_t i = 0; i < len; i++) {
        ss << hex << setw(2) << setfill('0') << static_cast<int>(data[i]);
    }
    return ss.str();
}

string AccountManager::hashPassword(const string& password, const string& salt) const {
    string salted_password = salt + password;
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hash_len;

    EVP_MD_CTX* ctx = EVP_MD_CTX_new();
    if (!ctx) throw runtime_error("Failed to create EVP context");

    if (EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr) != 1 ||
        EVP_DigestUpdate(ctx, salted_password.c_str(), salted_password.size()) != 1 ||
        EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1) {
        EVP_MD_CTX_free(ctx);
        throw runtime_error("Password hashing failed");
    }
    EVP_MD_CTX_free(ctx);

    return hexEncode(hash, hash_len);
}

bool AccountManager::createAccount(const string& username, const string& password) {
    if (username.empty() || 
        !all_of(username.begin(), username.end(), [](char c) {
            return isalnum(c);
        })) {
        cerr << "Error: 用户名必须为字母数字组合" << endl;
        return false;
    }
    
    if (password.length() < 6 || 
        !any_of(password.begin(), password.end(), [](char c) { return isdigit(c); }) ||
        !any_of(password.begin(), password.end(), [](char c) { return isalpha(c); })) {
        cerr << "Error: 密码至少6位且包含字母和数字" << endl;
        return false;
    }
    
    if (accountExists(username)) {
        cerr << "Error: 用户名已存在" << endl;
        return false;
    }
    
    UserAccount new_account;
    new_account.username = username;
    new_account.salt = generateSalt();
    new_account.password_hash = hashPassword(password, new_account.salt);
    
    accounts.push_back(new_account);
    saveAccountsToFile();
    return true;
}

bool AccountManager::authenticate(const string& username, const string& password) const {
    auto it = find_if(accounts.begin(), accounts.end(), 
        [&](const UserAccount& acc) { return acc.username == username; });
    
    if (it != accounts.end()) {
        string hashed_input = hashPassword(password, it->salt);
        return hashed_input == it->password_hash;
    }
    return false;
}

bool AccountManager::accountExists(const string& username) const {
    return any_of(accounts.begin(), accounts.end(), 
        [&](const UserAccount& acc) { return acc.username == username; });
}

bool AccountManager::changePassword(const string& username, const string& new_password) {
    auto it = find_if(accounts.begin(), accounts.end(), 
        [&](const UserAccount& acc) { return acc.username == username; });
    
    if (it != accounts.end()) {
        it->salt = generateSalt();
        it->password_hash = hashPassword(new_password, it->salt);
        saveAccountsToFile();
        return true;
    }
    return false;
}

void AccountManager::saveAccountsToFile() const {
    ofstream file(account_file_path);
    if (!file) {
        cerr << "Error: 无法保存账户文件" << endl;
        return;
    }
    
    for (const auto& account : accounts) {
        file << account.username << ":" 
             << account.password_hash << ":" 
             << account.salt << "\n";
    }
}

void AccountManager::loadAccountsFromFile() {
    accounts.clear();
    ifstream file(account_file_path);
    if (!file) return;
    
    string line;
    while (getline(file, line)) {
        size_t pos1 = line.find(':');
        size_t pos2 = line.find(':', pos1 + 1);
        
        if (pos1 != string::npos && pos2 != string::npos) {
            UserAccount account;
            account.username = line.substr(0, pos1);
            account.password_hash = line.substr(pos1 + 1, pos2 - pos1 - 1);
            account.salt = line.substr(pos2 + 1);
            accounts.push_back(account);
        }
    }
}
